home *** CD-ROM | disk | FTP | other *** search
- Path: xanth!cs.odu.edu!Amiga-Request
- From: Amiga-Request@cs.odu.edu (Amiga Sources/Binaries Moderator)
- Newsgroups: comp.sources.amiga
- Subject: v90i030: Trackutils - utilities to allocate and copy disk tracks, Part02/02
- Message-ID: <11070@xanth.cs.odu.edu>
- Date: 20 Jan 90 15:38:03 GMT
- Sender: tadguy@cs.odu.edu
- Reply-To: Eddy Carroll <ECARROLL%vax1.tcd.ie@CUNYVM.CUNY.EDU>
- Lines: 1391
- Approved: tadguy@cs.odu.edu (Tad Guy)
-
- Submitted-by: Eddy Carroll <ECARROLL%vax1.tcd.ie@CUNYVM.CUNY.EDU>
- Posting-number: Volume 90, Issue 030
- Archive-name: util/trackutils/part02
-
- #!/bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 2 (of 2)."
- # Contents: src/tfile.c
- # Wrapped by tadguy@xanth on Sat Jan 20 10:37:18 1990
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'src/tfile.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'src/tfile.c'\"
- else
- echo shar: Extracting \"'src/tfile.c'\" \(38195 characters\)
- sed "s/^X//" >'src/tfile.c' <<'END_OF_FILE'
- X/*
- X * TFILE.C
- X *
- X * (C) Copyright Eddy Carroll, January 1990
- X *
- X * This is a little utility which simply creates a "fake" file on a disk,
- X * which makes AmigaDos think that all the blocks on a given range of
- X * tracks are in use. I.e. it allows you to reserve a section of the disk
- X * for your own messing around, without fear of AmigaDos stomping over you
- X * at some later stage.
- X *
- X * Usage: tfile <pathname> <start> <end>
- X *
- X * <pathname> The full pathname of the filename AmigaDOS will think
- X * the blocks are stored in. This also specifies the device
- X * on which the blocks are to be reserved.
- X *
- X * <start> The starting track to reserve blocks on.
- X *
- X * <end> The ending track to reserve blocks on.
- X *
- X * For example, to reserve tracks 70 to 79 on the disk in DF0:, you might
- X * give the command:
- X *
- X * tfile df0:devs/Tracks70-79 70 79
- X *
- X * which will create the file devs/Tracks70-79 on the disk in DF0: If you
- X * try and actually access this file, you will find it only contains a brief
- X * message -- this is a safeguard to stop AmigaDOS trying to make sense
- X * of whatever data is actually on tracks 70 to 79.
- X *
- X * Tfile is primarily intended for use with the companion program tcopy,
- X * which allows tracks from a small device such as RAD: to be stored on
- X * part of a larger device like a floppy disk, and then read back in at
- X * a later time (and at high speed).
- X *
- X *
- X * Note: The following assumptions are hardwired into the code --
- X *
- X * -- Long's are at least 32 bits long
- X * -- Blocks are 512 bytes long
- X * -- Either the old or fast filing system is in use
- X */
- X
- X#define TRUE 1
- X#define FALSE 0
- X#define LASTCHAR(s) (s[strlen(s)-1])
- X
- X#ifndef LATTICE_50
- X#include "system.h"
- X#endif
- X
- X#include "dosheaders.h"
- X
- X#define MIN(x,y) ((x) < (y) ? (x) : (y))
- X
- Xextern struct DosLibrary *DOSBase;
- X
- Xtypedef struct IORequest IOREQ;
- Xtypedef struct MsgPort MSGPORT;
- Xtypedef struct Process PROC;
- Xtypedef struct StandardPacket STDPKT;
- X
- Xvoid inhibit(MSGPORT *devport, int mode); /* Called by cleanup() */
- X
- X
- X/*
- X * This is the message that gets stored in the dummy file when
- X * the disk being written to is an OFS disk. Max 488 characters please.
- X */
- Xchar FileMessage[] = "\
- XThis file was created using TFile (C) Copyright Eddy Carroll 1990.\n\n\
- XTFile creates special files which don't contain data, but instead prevent\n\
- XAmigaDOS from overwriting the information on some tracks on this disk.\n\n";
- X
- X
- X/*
- X * Structure representing a disk device
- X */
- Xtypedef struct {
- X char *devname; /* Name of exec device for this disk */
- X int isfloppy; /* True if device is trackdisk.device */
- X int isffs; /* True if device is using FFS */
- X int isknown; /* True if filesystem is known */
- X ULONG unit; /* Unit number of above exec device */
- X ULONG blocksize; /* Number of bytes per block */
- X ULONG blockspertrack; /* Number of blocks/sectors per track */
- X ULONG surfaces; /* Number of tracks per cylinder */
- X ULONG lowcyl; /* Starting cylinder of disk on device */
- X ULONG numcyl; /* Number of cylinders on this disk */
- X ULONG numblocks; /* Number of blocks on this disk */
- X ULONG reserved; /* Number of blocks reserved at start */
- X /* (included in numblocks count) */
- X} DISKDEV;
- X
- X/*
- X * Global variables
- X * ----------------
- X */
- X
- XBPTR filehandle; /* Filehandle used when creating dummy file */
- XBPTR lock; /* Lock on dummy file used to store tracks */
- XLONG filekey; /* AmigaDOS block of dummy file header */
- Xchar *pathname; /* Full AmigaDOS path of file to create */
- Xchar devname[300]; /* AmigaDOS device we are operating on */
- XDISKDEV diskdev[1]; /* Description of disk device we are using */
- Xstruct IOStdReq *req; /* Standard request for source device */
- XMSGPORT *reqport; /* Message port for replies from disk dev. */
- XMSGPORT *diskport; /* Message port of process of disk device */
- Xint devopen; /* True if disk exec device is open */
- Xint inhibited; /* True if destination device is inhibited */
- Xvoid *readbuf; /* Buffer to read a single disk block into */
- Xvoid *writebuf; /* Buffer to write a single disk block from */
- XULONG *bitmap; /* Array of longwords holding bitmap */
- XULONG *bitmapblocks; /* Array of block numbers for disk bitmap */
- XULONG bitmapsize; /* Size of bitmap in bytes */
- XULONG bitmapblocksize; /* Size of bitmap blocks array in bytes */
- XULONG numbitmapblocks; /* Number of blocks storing bitmap on disk */
- Xstruct FileHeaderBlock *headers; /* Array of file headers/extensions */
- Xstruct DataBlock *datablock; /* Datablock used if accessing OFS */
- Xstruct RootBlock *rootblock; /* Rootblock of current disk */
- XULONG headersize; /* Size of array of file headers in bytes */
- XULONG datasize; /* Size of datablock in bytes */
- XULONG rootsize; /* Size of rootblock in bytes */
- XULONG datablocknum; /* Block # to store front data block at */
- X
- X
- X/*
- X * print()
- X * -------
- X * Outputs a message to stdout
- X */
- Xvoid print(char *s)
- X{
- X Write(Output(), s, strlen(s));
- X}
- X#define print2(s1,s2) (print(s1),print(s2))
- X#define print3(s1,s2,s3) (print(s1),print(s2),print(s3))
- X
- X/*
- X * numtostr()
- X * ----------
- X * Simple little function which returns a pointer to a static string
- X * representation of the passed in number.
- X */
- Xchar *numtostr(int n)
- X{
- X static char s[20];
- X int i = 19;
- X
- X s[19] = '\0';
- X if (n)
- X while (n) {
- X s[--i] = '0' + (n % 10);
- X n /= 10;
- X }
- X else
- X s[--i] = '0';
- X return(&s[i]);
- X}
- X
- X
- X/*
- X * cleanup()
- X * ---------
- X * Closes all opened resources, and exits with specified error code.
- X */
- Xvoid cleanup(int code)
- X{
- X if (devopen) {
- X if (diskdev->isfloppy) { /* Turn off drive motor if floppy disk */
- X req->io_Command = TD_MOTOR;
- X req->io_Length = 0;
- X DoIO(req);
- X }
- X CloseDevice((IOREQ *)req);
- X }
- X if (inhibited)
- X inhibit(diskport, FALSE);
- X if (readbuf)
- X FreeMem(readbuf, diskdev->blocksize);
- X if (writebuf)
- X FreeMem(writebuf, diskdev->blocksize);
- X if (req)
- X DeleteStdIO(req);
- X if (reqport)
- X DeletePort(reqport);
- X if (lock)
- X UnLock(lock);
- X if (filehandle)
- X Close(filehandle);
- X if (bitmap)
- X FreeMem(bitmap, bitmapsize);
- X if (bitmapblocks)
- X FreeMem(bitmapblocks, bitmapblocksize);
- X if (headers)
- X FreeMem(headers, headersize);
- X if (datablock)
- X FreeMem(datablock, datasize);
- X if (rootblock)
- X FreeMem(rootblock, rootsize);
- X exit(code);
- X}
- X
- X
- X/*
- X * chkabort()
- X * ----------
- X * A replacement for Lattice's chkabort(), which doesn't carry all
- X * the extra baggage. If CTRL-C is detected, this function never
- X * returns but instead calls cleanup. Since Lattice's exit() code
- X * may call chkabort(), a check is made to ensure that cleanup()
- X * only gets called once, otherwise there would be a problem if the
- X * user pressed Ctrl-C twice in quick succession.
- X */
- Xvoid chkabort(void)
- X{
- X static int gotctrlc = FALSE;
- X if (!gotctrlc && (SetSignal(0,0) & SIGBREAKF_CTRL_C)) {
- X gotctrlc = TRUE;
- X print("^C\n");
- X cleanup(10);
- X }
- X}
- X
- X
- X/*
- X * GetVolume()
- X * -----------
- X * This function searches the device list looking for a physical device
- X * that currently contains the specified disk volume. When it finds it,
- X * it fills in the DISKDEV structure with information about the physical
- X * device which can then be used to access it at the block level.
- X */
- Xint GetVolume(char *devname, DISKDEV *dev)
- X{
- X struct RootNode *rootnode;
- X struct DosInfo *dosinfo;
- X struct DeviceNode *devnode;
- X struct FileSysStartupMsg *startup;
- X struct DosEnvec *dosenvec;
- X unsigned char *p;
- X int namelen = strlen(devname);
- X
- X if (LASTCHAR(devname) != ':') /* Device names must end with ':' */
- X return (FALSE);
- X /*
- X * First of all, find the device
- X */
- X rootnode = (struct RootNode *)DOSBase->dl_Root;
- X dosinfo = (struct DosInfo *)BADDR(rootnode->rn_Info);
- X devnode = (struct DeviceNode *)BADDR(dosinfo->di_DevInfo);
- X
- X Forbid(); /* Make sure list doesn't change while we scan it */
- X
- X while (devnode != NULL) {
- X p = (unsigned char *)BADDR(devnode->dn_Name)+1;
- X if (!strnicmp(devname, p, namelen-1)) { /* Don't compare the ':' */
- X /*
- X * Matched name successfully. Now check if it's a device.
- X * Note that we carry on searching if it's not a device
- X * (rather than returning FALSE immediately) since there
- X * may be a volume called RAD: as well as a device called
- X * RAD:, for example.
- X */
- X if (devnode->dn_Type == DLT_DEVICE) {
- X if (devnode->dn_Startup < 20) /* Is there a startup bit? */
- X goto notfound; /* If not, not disk device */
- X /* Eek! A GOTO! */
- X
- X startup = (struct FileSysStartupMsg *)
- X BADDR(devnode->dn_Startup);
- X
- X if (dev) {
- X dev->devname = ((char *)BADDR(startup->fssm_Device))+1;
- X dev->isfloppy = (!strcmp(TD_NAME, dev->devname));
- X dev->unit = startup->fssm_Unit;
- X }
- X
- X if (startup->fssm_Environ < 20)
- X goto notfound;
- X /* Another GOTO! The world will end in 5 seconds... */
- X
- X dosenvec = (struct DosEnvec *)BADDR(startup->fssm_Environ);
- X
- X if (dev) {
- X dev->isffs = dosenvec->de_DosType == 0x444F5301;
- X /*
- X * Since dosenvec->de_DosType does NOT equal
- X * 0x444F5300 for standard OFS AmigaDOS disks,
- X * I can't check it to see if the filing system
- X * is "known". Hence, for now, just assume its
- X * always known (since it can currently only be
- X * OFS or FFS, and I can't think of any other way
- X * of checking).
- X */
- X dev->isknown = 1;
- X dev->blocksize = dosenvec->de_SizeBlock << 2;
- X dev->blockspertrack = dosenvec->de_BlocksPerTrack;
- X dev->surfaces = dosenvec->de_Surfaces;
- X dev->lowcyl = dosenvec->de_LowCyl;
- X dev->numcyl = (dosenvec->de_HighCyl -
- X dosenvec->de_LowCyl) + 1;
- X dev->numblocks = dev->blockspertrack * dev->surfaces
- X * dev->numcyl;
- X dev->reserved = dosenvec->de_Reserved;
- X }
- X Permit();
- X return (TRUE);
- X }
- X }
- X devnode = (struct DeviceNode *)BADDR(devnode->dn_Next);
- X }
- Xnotfound:
- X Permit();
- X return (FALSE);
- X}
- X
- X/*
- X * help()
- X * ------
- X * Prints out a help message about trackfile
- X */
- Xvoid help(void)
- X{
- X print3(
- X"Trackfile (C) Copyright Eddy Carroll, January 1990. Freely distributable.\n",
- X"Creates an AmigaDos file which reserves specified tracks on a disk.\n\n",
- X"Usage: tfile <pathname> <start> <end>\n\n"); print3(
- X" <pathname> The full AmigaDOS path of the dummy file that will be \
- Xcreated\n",
- X" to hold the reserved tracks, to stop AmigaDOS using them.\n\n",
- X" <start> The starting track to be reserved on the disk.\n\n" ); print(
- X" <end> The ending track to be reserved on the disk.\n\n" );
- X}
- X
- X
- X/*
- X * opendev()
- X * ---------
- X * Opens the disk device, allocates stdreqs etc. Two buffers are
- X * also allocated, one for reading a single block and one for
- X * writing a single block.
- X */
- Xvoid opendev(void)
- X{
- X ULONG memflags = MEMF_PUBLIC;
- X
- X if (diskdev->isfloppy)
- X memflags |= MEMF_CHIP;
- X
- X reqport = (MSGPORT *)CreatePort(0,0);
- X if (!reqport) {
- X print("Couldn't allocate message port\n");
- X cleanup(10);
- X }
- X
- X readbuf = AllocMem(diskdev->blocksize, memflags);
- X if (!readbuf) {
- X print("Couldn't allocate memory for read buffer\n");
- X cleanup(10);
- X }
- X
- X writebuf = AllocMem(diskdev->blocksize, memflags);
- X if (!writebuf) {
- X print("Couldn't allocate memory for write buffer\n");
- X cleanup(10);
- X }
- X
- X req = CreateStdIO(reqport);
- X if (!req) {
- X print("Couldn't allocate IO request - memory is low!\n");
- X cleanup(10);
- X }
- X
- X if (OpenDevice(diskdev->devname, diskdev->unit, (IOREQ *)req, 0L)) {
- X print3("Can't open device ", diskdev->devname, "\n");
- X cleanup(10);
- X }
- X devopen = TRUE;
- X}
- X
- X/*
- X * readblock() & writeblock()
- X * ----------- ------------
- X *
- X * These two functions read or write a block from the disk.
- X * See the definition of transferblocks() below for more information.
- X */
- X#define BLOCK_READ 0
- X#define BLOCK_WRITE 1
- X
- X#define readblock(buffer, s) transferblocks(buffer, s, 1, BLOCK_READ)
- X#define writeblock(buffer, s) transferblocks(buffer, s, 1, BLOCK_WRITE)
- X
- X/*
- X * transferblocks()
- X * ----------------
- X * Transfers n blocks to/from the disk into the buffer indicated,
- X * starting at block s. Note that if you are using a floppy drive, the
- X * buffer MUST be allocated in CHIP ram! You can ensure this by
- X * including MEMF_CHIP in the flags to AllocMem() if diskdev->isfloppy
- X * is true. Zero is returned if an error occurred, else non-zero.
- X * Up to three retries are done before failure is accepted.
- X *
- X * The direction of transfer is BLOCK_READ to read blocks in, or
- X * BLOCK_WRITE to write blocks out.
- X */
- Xint transferblocks(void *buffer, int s, int n, int direction)
- X{
- X int retry, parstart;
- X
- X /*
- X * Because AmigaDOS works with partitions, Block 0 of an AmigaDOS
- X * device may in fact be block 12345 of an exec device, depending
- X * where the partition starts. Hence, before trying to access an
- X * Amiga-DOS numbered block, we need to add in the block at which
- X * the current partition starts.
- X */
- X parstart = diskdev->lowcyl * diskdev->blockspertrack * diskdev->surfaces;
- X
- X /*
- X * Now read in blocks from disk
- X */
- X for (retry = 0; retry < 3; retry++) {
- X if (direction == BLOCK_READ)
- X req->io_Command = CMD_READ;
- X else
- X req->io_Command = CMD_WRITE;
- X req->io_Length = diskdev->blocksize * n;
- X req->io_Offset = diskdev->blocksize * (s + parstart);
- X req->io_Data = buffer;
- X if (!DoIO((IOREQ *)req))
- X break; /* Succeeded, so break out of loop */
- X }
- X if (retry == 3)
- X return (0);
- X else
- X return (1);
- X}
- X
- X/*
- X * SendPacket()
- X * ------------
- X * ``Sort of'' simulates the ARP SendPacket() routine which sends
- X * a packet to AmigaDos, and gets a reply if appropriate. What is
- X * passed in is the action to be executed (one of the ACTION_xxx
- X * definitions in dosextens.h), a pointer to a longword array of 7
- X * arguments to be passed to the device, and the msgport of the device
- X * as returned by DeviceProc("DF0:") for example. If result is non-NULL
- X * then it should be a pointer to a two element array of ULONGs, and it
- X * fills in the 0th element with the primary result, and the the
- X * 1st element with the secondary result.
- X */
- Xint SendPacket(ULONG action, void *args, MSGPORT *devport, ULONG *result)
- X{
- X PROC *proc = (PROC *)FindTask(NULL);
- X STDPKT *packet;
- X
- X packet = (STDPKT *)AllocMem(sizeof(STDPKT), MEMF_CLEAR | MEMF_PUBLIC);
- X if (!packet)
- X return (FALSE);
- X packet->sp_Msg.mn_Node.ln_Name = (char *)&packet->sp_Pkt;
- X packet->sp_Pkt.dp_Link = &packet->sp_Msg;
- X packet->sp_Pkt.dp_Port = &proc->pr_MsgPort;
- X packet->sp_Pkt.dp_Type = action;
- X memcpy(&packet->sp_Pkt.dp_Arg1, args, sizeof(ULONG) * 7);
- X
- X /*
- X * Okay, we've done the necessary magic to create an AmigaDos
- X * packet lookalike (thanks to Matt Dillon in Transactor V1.1).
- X * Now we send the message to the Dos process, and get the reply.
- X * Then our message will be filled in with the response from the
- X * Dos process.
- X */
- X PutMsg(devport, (struct Message *)packet);
- X WaitPort(&proc->pr_MsgPort);
- X GetMsg(&proc->pr_MsgPort);
- X if (result) {
- X result[0] = packet->sp_Pkt.dp_Res1;
- X result[1] = packet->sp_Pkt.dp_Res2;
- X }
- X FreeMem(packet, sizeof(STDPKT));
- X return (TRUE);
- X}
- X
- X
- X/*
- X * inhibit()
- X * ---------
- X * This function inhibits (if mode is TRUE) or uninhibits (if mode is
- X * FALSE) the specified device.
- X */
- Xvoid inhibit(MSGPORT *devport, int mode)
- X{
- X ULONG pktargs[7];
- X int i;
- X
- X pktargs[0] = mode; /* Select inhibit or opposite */
- X for (i = 1; i < 7; i++) /* Clear other arguments */
- X pktargs[i] = 0;
- X
- X if (!SendPacket(ACTION_INHIBIT, pktargs, devport, NULL)) {
- X print("Couldn't send inhibit packet to device\n");
- X cleanup(10);
- X }
- X}
- X
- X
- X/*
- X * flushdisk()
- X * -----------
- X * This function flushes the specified DOS device, ensuring that all
- X * dirty buffers are written to disk and the bitmap is up to date.
- X */
- Xvoid flushdisk(MSGPORT *devport)
- X{
- X ULONG pktargs[7];
- X int i;
- X
- X for (i = 0; i < 7; i++) /* Clear arguments */
- X pktargs[i] = 0;
- X
- X if (!SendPacket(ACTION_FLUSH, pktargs, devport, NULL)) {
- X print("Couldn't send flush packet to device\n");
- X cleanup(10);
- X }
- X}
- X
- X/*
- X * fixchecksum()
- X * -------------
- X * Calculates the checksum for the specified block, and stores it
- X * in the indicated place, which will usually be a pointer into the
- X * block itself. The block is assumed to be 512 bytes long.
- X */
- Xvoid fixchecksum(void *block, ULONG *checksum)
- X{
- X ULONG *blk = block, *start, *end;
- X ULONG sum = 0;
- X
- X end = blk + 128;
- X *checksum = 0; /* Clear checksum so it won't affect count */
- X
- X for (start = blk; start < end; start++)
- X sum += *start;
- X
- X *checksum = -sum; /* Real checksum is complement of total */
- X}
- X
- X/*
- X * readrootblock()
- X * ---------------
- X * This function simply reads in the root block of the disk into
- X * the global 'root' structure for the rest of the program to access.
- X */
- Xvoid readrootblock(void)
- X{
- X ULONG rootblocknum = diskdev->numblocks / 2;
- X ULONG memflags = MEMF_PUBLIC;
- X
- X if (diskdev->isfloppy)
- X memflags |= MEMF_CHIP;
- X
- X rootsize = 512;
- X rootblock = AllocMem(rootsize, memflags);
- X if (!rootblock) {
- X print("Out of memory allocating space for root block\n");
- X cleanup(10);
- X }
- X if (!readblock(rootblock, rootblocknum)) {
- X print("Error reading root block from disk\n");
- X cleanup(10);
- X }
- X}
- X
- X
- X#ifdef DEBUG
- X/*
- X * writerootblock()
- X * ----------------
- X * This function writes the rootblock back to disk.
- X * Temporarily, it zaps the "validated" flag to force a validation
- X * to occur.
- X */
- Xvoid writerootblock(void)
- X{
- X ULONG rootblocknum = diskdev->numblocks / 2;
- X
- X rootblock->BitmapFlag = 0;
- X fixchecksum(rootblock, &rootblock->Checksum);
- X writeblock(rootblock, rootblocknum);
- X}
- X
- X#endif
- X
- X
- X/*
- X * readbitmap()
- X * ------------
- X *
- X * This function creates a memory copy of the disks's bitmap, by
- X * reading in all the disk's bitmap blocks. Two arrays are created;
- X * The first holds the bitmap data itself, the second is a longword
- X * array holding the block numbers that the bitmap is stored on, for
- X * use when it is being written out again.
- X *
- X * If an error occurs, the function prints a message and exits to dos.
- X * It is assumed that the root block has been read in to 'root' before
- X * calling this function.
- X */
- Xvoid readbitmap(void)
- X{
- X int i, end;
- X ULONG nextblock;
- X ULONG *block = readbuf;
- X
- X /*
- X * First let's calculate the size of each array. The size of the
- X * bitmap array is simply the number of blocks on the disk divided
- X * by 8 (since a single byte can represent 8 blocks). The size of
- X * the array to hold the locations of the bitmap blocks is the
- X * number of blocks divided by 4064, since each bitmap block
- X * can represent 4064 disk blocks (with 32 bits left over for
- X * the block checksum).
- X */
- X
- X /*
- X * To calculate the number of DOS-usable blocks on the disk, we need
- X * to subtract the number of blocks reserved at the start of the
- X * partition. In addition, we add on 4063 so that the result after
- X * division will be rounded up to the next integral block number.
- X */
- X numbitmapblocks = (diskdev->numblocks + 4063 - diskdev->reserved) / 4064;
- X bitmapsize = numbitmapblocks * 508; /* 4 bytes used for checksum */
- X bitmapblocksize = numbitmapblocks * 4;
- X
- X /*
- X * Now, allocate the arrays
- X */
- X bitmap = AllocMem(bitmapsize, 0L);
- X if (!bitmap) {
- X print("Can't allocate memory to store disk bitmap.\n");
- X cleanup(10);
- X }
- X bitmapblocks = AllocMem(bitmapblocksize, 0L);
- X if (!bitmapblocks) {
- X print("Can't allocate memory to store disk bitmap sector numbers.\n");
- X cleanup(10);
- X }
- X
- X /*
- X * Now, read in all the sector numbers from the root block
- X */
- X end = MIN(numbitmapblocks, 25);
- X for (i = 0; i < end; i++)
- X bitmapblocks[i] = rootblock->BitmapKeys[i];
- X
- X /*
- X * If we are using a large disk partition (larger than 52 Megs or so)
- X * we also need to read in the bitmap extension block(s). Each
- X * extension block contains 127 sector numbers.
- X *
- X * Note: Since I am unsure of the extension bitmap format used,
- X * this code is being commented out for now, and a check has been
- X * included in main() to ensure no disk big enough to have an
- X * bitmap extension is allowed to get here; when I find out the
- X * format, it will be trivial to add support for it here, since the
- X * rest of the program just deals with an array of bitmap sector
- X * numbers (and the bitmap array itself of course).
- X *
- X * For the code, I'm assuming the bitmap is stored back to front
- X * (i.e. first sector last), based on Betty Clay's article in
- X * Transactor. I want to verify this first though before letting
- X * it loose on the unsuspecting public (after all, a bug that screws
- X * up a 50 Mb disk is not going to go down well with people who
- X * have 50 Mb disks... :-)
- X */
- X
- X nextblock = rootblock->BitmapExtend;
- X
- X#ifdef FOUND_OUT_HOW_THE_BITMAP_IS_STORED
- X
- X while (i < numbitmapblocks) {
- X int p = 127;
- X
- X if (!readblock(block, nextblock)) {
- X print("Error reading bitmap extension block from disk\n");
- X cleanup(10);
- X }
- X nextblock = block[0];
- X end = MIN(i + 127, numbitmapblocks);
- X while (i < end)
- X bitmapblocks[i++] = blocks[p--];
- X }
- X
- X#endif
- X
- X /*
- X * Now I know what sectors the bitmap itself is stored on, so
- X * I can read it in to memory.
- X */
- X for (i = 0; i < numbitmapblocks; i++) {
- X if (!readblock(block, bitmapblocks[i])) {
- X print("Error reading in bitmap from disk\n");
- X cleanup(10);
- X }
- X /*
- X * Remember, bitmap is pointer to ULONG so we use longword
- X * offsets when copying the bitmap data into the bitmap array.
- X */
- X memcpy(bitmap + (127 * i), block + 1, 508);
- X }
- X}
- X
- X/*
- X * writebitmap()
- X * -------------
- X * Writes the disk bitmap back to disk, storing it on the sectors
- X * it was read in from earlier.
- X */
- Xvoid writebitmap(void)
- X{
- X ULONG *diskblock = (ULONG *)writebuf;
- X int i;
- X
- X for (i = 0; i < numbitmapblocks; i++) {
- X /*
- X * For each bitmap block, copy the 127 longwords into write
- X * buffer, correct checksum, then write to disk.
- X */
- X memcpy(diskblock + 1, bitmap + (i * 127), 508);
- X fixchecksum(diskblock, &diskblock[0]);
- X if (!writeblock(diskblock, bitmapblocks[i])) {
- X print(
- X"Error writing updated bitmap to disk! Copy important files to a new disk!\n");
- X cleanup(10);
- X }
- X }
- X}
- X
- X#ifdef DEBUG
- X/*
- X * dumpbitmap()
- X * ------------
- X * A quick hack function to display the bitmap on screen, to allow
- X * visual confirmation that it was read in correctly, altered
- X * properly etc.
- X */
- Xvoid dumpbitmap(void)
- X{
- X int t, s, c, blocknum, i;
- X static char buf[300];
- X
- X for (c = 0; c < diskdev->numcyl; c++) {
- X for (t = 0; t < diskdev->surfaces; t++) {
- X
- X blocknum = (((c * diskdev->surfaces) + t)
- X * diskdev->blockspertrack);
- X chkabort();
- X print3(numtostr(c),",",numtostr(t));
- X print3(": ",numtostr(blocknum),"; ");
- X i = 0;
- X for (s = 0; s < diskdev->blockspertrack; s++) {
- X blocknum = (((c * diskdev->surfaces) + t)
- X * diskdev->blockspertrack) + s;
- X if (blocknum < diskdev->reserved ||
- X blocknum >= diskdev->numblocks)
- X buf[i++] = 'O'; /* Block reserved */
- X else {
- X blocknum = blocknum - diskdev->reserved;
- X if (bitmap[blocknum >> 5] & (1 << (blocknum & 31)))
- X buf[i++] = '-'; /* Block unused */
- X else
- X buf[i++] = 'O'; /* Block in use */
- X }
- X }
- X buf[i] = '\0';
- X print2(buf, "\n");
- X }
- X }
- X}
- X#endif
- X
- X/*
- X * filltracks()
- X * ------------
- X * Tries to mark the specified cylinders as used in the memory copy
- X * of the disk bitmap. 1 is returned if successful, 0 if any of the
- X * blocks in the cylinders were already in use.
- X */
- Xint filltracks(int lowcyl, int highcyl)
- X{
- X long startblock, endblock; /* Adjusted block numbers */
- X long startblockindex, endblockindex; /* Indexes into bitmap array */
- X long startoffset, endoffset; /* Bit offsets into bitmap word */
- X long lastblock; /* Last bitmap block on disk */
- X int i, warn = 0;
- X
- X lastblock = diskdev->numblocks - diskdev->reserved;
- X
- X startblock = lowcyl * diskdev->surfaces * diskdev->blockspertrack
- X - diskdev->reserved;
- X if (startblock < 0) {
- X warn = 1;
- X startblock = 0;
- X }
- X if (startblock >= lastblock) {
- X warn = 1;
- X startblock = lastblock;
- X }
- X startblockindex = startblock >> 5;
- X startoffset = startblock & 31;
- X
- X endblock = (highcyl + 1) * diskdev->surfaces * diskdev->blockspertrack
- X - diskdev->reserved;
- X if (endblock < 0) {
- X warn = 1;
- X endblock = 0;
- X }
- X if (endblock > lastblock) {
- X warn = 1;
- X endblock = lastblock;
- X }
- X endblockindex = endblock >> 5;
- X endoffset = endblock & 31;
- X
- X if (warn)
- X print("(Warning: Track range includes reserved portion of disk.)\n");
- X
- X if (startblockindex == endblockindex) {
- X /*
- X * Start and stop in same bitmap word, so set the bits manually
- X */
- X for (i = startoffset; i < endoffset; i++) {
- X if ((bitmap[startblockindex] & (1 << i)) == 0)
- X return (0); /* Block already in use */
- X else
- X bitmap[startblockindex] &= ~(1 << i); /* Clear bit in bitmap */
- X }
- X return (1);
- X }
- X
- X /*
- X * Allocate first few blocks a bit at a time up to end of longword
- X */
- X for (i = startoffset; i < 32; i++) {
- X if ((bitmap[startblockindex] & (1 << i)) == 0)
- X return (0); /* Block already in use */
- X else
- X bitmap[startblockindex] &= ~(1 << i); /* Clear bit in bitmap */
- X }
- X
- X /*
- X * Now allocate inbetween blocks a longword at a time for speed
- X */
- X for (i = startblockindex + 1; i < endblockindex; i++) {
- X if (bitmap[i] != 0xffffffff)
- X return (0); /* Block already in use */
- X else
- X bitmap[i] = 0; /* Set all blocks used */
- X }
- X
- X /*
- X * Finally, allocate last few blocks a bit at a time
- X */
- X for (i = 0; i < endoffset; i++) {
- X if ((bitmap[endblockindex] & (1 << i)) == 0)
- X return (0); /* Block already in use */
- X else
- X bitmap[endblockindex] &= ~(1 << i); /* Clear bit in bitmap */
- X }
- X return (1);
- X}
- X
- X/*
- X * allocblock()
- X * ------------
- X * Tries to allocate a block as close to block `key' as possible,
- X * from the remaining free blocks in the disk bitmap. The allocation
- X * algorithm is as follows:
- X *
- X * - Find the nearest free block before the key
- X * - Find the nearest free block after the key
- X * - Allocate whichever one is closest
- X *
- X * If the allocation was successful, the number of the new block is
- X * stored in newkey.
- X */
- Xint allocblock(ULONG key, ULONG *newkey)
- X{
- X ULONG curblock = key - diskdev->reserved;
- X ULONG endblock = diskdev->numblocks - diskdev->reserved;
- X ULONG endindex = endblock >> 5;
- X ULONG useblock;
- X long i, j, tp; /* Must be signed */
- X long curindex = curblock >> 5;
- X long curoffset = curblock & 31;
- X int backblock = -1, forblock = -1;
- X
- X /*
- X * Find nearest block before current key. Remember that in the
- X * bitmap, a `1' means the block is free, a `0' means its allocated.
- X *
- X * First of all, search back within current bitmap word
- X */
- X tp = bitmap[curindex];
- X for (i = curoffset; i >= 0; i--) {
- X if (tp & (1 << i)) {
- X backblock = (curindex << 5) + i;
- X break;
- X }
- X }
- X
- X if (backblock < 0) {
- X /*
- X * Didn't find room in initial word, so carry on search
- X */
- X for (i = curindex - 1; i >= 0; i--) {
- X if (bitmap[i] != 0) {
- X tp = bitmap[i];
- X /*
- X * Found free block word; now find what bit it is;
- X * Note that because of the way we entered this
- X * loop (with tp != 0), termination of the next
- X * loop is guaranteed.
- X */
- X for (j = 31; (tp & (1 << j)) == 0; j--)
- X ;
- X backblock = (i << 5) + j;
- X break;
- X }
- X }
- X }
- X
- X /*
- X * Now find nearest block after current key
- X */
- X tp = bitmap[curindex];
- X for (i = curoffset; i < 32; i++) {
- X if (tp & (1 << i)) {
- X forblock = (curindex << 5) + i;
- X break;
- X }
- X }
- X
- X if (forblock < 0) {
- X /*
- X * Didn't find room in initial word, so carry on search
- X */
- X for (i = curindex + 1; i <= endindex; i--) {
- X if (bitmap[i] != 0) {
- X tp = bitmap[i];
- X /*
- X * Found free room; now find what bit it is;
- X * Note that because of the way we entered this
- X * loop (with tp != 0), termination of the next
- X * loop is guaranteed.
- X */
- X for (j = 0; (tp & (1 << j)) == 0; j++)
- X ;
- X forblock = (i << 5) + j;
- X break;
- X }
- X }
- X }
- X
- X /*
- X * Now, forblock and backblock hold block numbers which are free
- X * in the bitmap (or -1 if none was found). We just have to
- X * work out which one to use.
- X */
- X if (forblock < 0) {
- X if (backblock < 0)
- X return (0);
- X else
- X useblock = backblock;
- X } else {
- X if (backblock < 0)
- X useblock = forblock;
- X else {
- X if ((key - backblock) < (forblock - key))
- X useblock = backblock;
- X else
- X useblock = forblock;
- X }
- X }
- X
- X /*
- X * At this stage, useblock is the block number to allocate and
- X * return.
- X */
- X bitmap[useblock >> 5] &= ~(1 << (useblock & 31));
- X *newkey = useblock + diskdev->reserved;
- X /*
- X * Finally, a brief sanity check to ensure the number is in range
- X * It SHOULD be but it doesn't do any harm to check, in case we
- X * ran off the end of the bitmap or something...
- X */
- X if (*newkey < diskdev->numblocks)
- X return (1);
- X else
- X return (0);
- X}
- X
- X
- X/*
- X * createfileheaders()
- X * -------------------
- X * Allocates an array of file headers and extension blocks, and
- X * fills them in with the appropriate values to make AmigaDOS think
- X * a file exists on the tracks the user indictated. The key is
- X * the block number of the file header which is to be modified to
- X * hold the dummy file.
- X *
- X * As well as allocating the blocks on the tracks to be reserved,
- X * an additional `frontend' data block is stuck at the front of the
- X * file containing a brief message. This stops DOS from getting
- X * confused if the user tries to access the file. Under the FFS it
- X * isn't needed, but under the OFS, a series crash results. To stop
- X * the code getting overly complicated, the FFS gets it too.
- X *
- X * After the headers have been initialised, they are written back to
- X * the disk and hey presto, a new file is born :-)
- X */
- Xvoid createfileheaders(int key, int lowcyl, int highcyl)
- X{
- X static char msgbuf[488];
- X ULONG lastblock, startblock, endblock, numblocks, filesize;
- X ULONG curblock;
- X ULONG memflags = MEMF_PUBLIC | MEMF_CLEAR;
- X int i, j, numheaders;
- X
- X lastblock = diskdev->numblocks;
- X
- X startblock = lowcyl * diskdev->surfaces * diskdev->blockspertrack;
- X if (startblock < diskdev->reserved)
- X startblock = diskdev->reserved;
- X
- X endblock = (highcyl + 1) * diskdev->surfaces * diskdev->blockspertrack;
- X if (endblock > lastblock)
- X endblock = lastblock;
- X
- X numblocks = 1 + endblock - startblock; /* 1 extra for front data block */
- X
- X /*
- X * Now, we know how many blocks the file will have (we've been
- X * careful not to count blocks which are reserved at the start
- X * or end of the partition). Next, let's calculate how many
- X * bytes our pretend file will have. This depends on whether
- X * the filing system is OFS or FFS.
- X */
- X if (diskdev->isffs)
- X filesize = numblocks * 512;
- X else
- X filesize = numblocks * 488;
- X
- X /*
- X * Now allocate the file header/extensions to hold the file.
- X * Each header/extension holds 72 block keys.
- X */
- X numheaders = (numblocks + 71) / 72;
- X headersize = numheaders * 512;
- X
- X if (diskdev->isfloppy)
- X memflags |= MEMF_CHIP;
- X
- X headers = AllocMem(headersize, memflags);
- X if (!headers) {
- X print("Error allocating memory for file header/extension blocks\n");
- X cleanup(10);
- X }
- X /*
- X * Read in file header block, for file to be modified.
- X */
- X if (!readblock(headers, key)) {
- X print("Error reading file header block from disk\n");
- X cleanup(10);
- X }
- X /*
- X * Now fill in the details for all the file extension blocks.
- X */
- X
- X curblock = startblock - 1; /* Adjust to allow for front data block */
- X
- X for (i = 0; i < numheaders; i++) {
- X int end = MIN(72, endblock - curblock);
- X
- X for (j = 0; j < end; j++)
- X headers[i].DataBlocks[71-j] = curblock++;
- X }
- X
- X for (i = 1; i < numheaders; i++) {
- X
- X headers[i].Type = Type_List;
- X headers[i].SecondaryType = SecType_File;
- X if (!allocblock(headers[i-1].OwnKey, &headers[i].OwnKey)) {
- X print("Not enough room on disk to store dummy file.\n");
- X cleanup(10);
- X }
- X headers[i-1].Extension = headers[i].OwnKey;
- X headers[i].HighSeq = 72;
- X headers[i].DataSize = 72;
- X headers[i].Parent = key;
- X }
- X headers[numheaders-1].Extension = 0;
- X headers[numheaders-1].HighSeq = numblocks % 72;
- X headers[numheaders-1].DataSize = numblocks % 72;
- X
- X headers[0].FileSize = filesize;
- X headers[0].HighSeq = numblocks;
- X
- X /*
- X * Now, allocate and save the dummy data block containing the
- X * brief message. Under the FFS, users can actually access the
- X * raw track data by seeking to (offset + 512), where offset is
- X * the desired byte offset from the first reserved cylinder.
- X */
- X datasize = 512;
- X datablock = AllocMem(datasize, memflags);
- X if (!datablock) {
- X print("Out of memory allocating temporary disk data block.\n");
- X cleanup(10);
- X }
- X if (!allocblock(key, &datablocknum)) {
- X print("Not enough room on disk to store dummy file.\n");
- X cleanup(10);
- X }
- X /*
- X * Now generate message containing track data.
- X */
- X strcpy(msgbuf, FileMessage);
- X if (lowcyl == highcyl) {
- X strcat(msgbuf, "This file contains disk track ");
- X strcat(msgbuf, numtostr(lowcyl));
- X } else {
- X strcat(msgbuf, "This file contains disk tracks ");
- X strcat(msgbuf, numtostr(lowcyl));
- X strcat(msgbuf, " to ");
- X strcat(msgbuf, numtostr(highcyl));
- X }
- X strcat(msgbuf, "\n\n");
- X
- X if (diskdev->isffs) {
- X /*
- X * For FFS, just put raw data into block.
- X */
- X strcpy((char *)datablock, msgbuf);
- X } else {
- X /*
- X * For OFS, fill in appropriate header details
- X */
- X datablock->Header = key;
- X datablock->Type = Type_Data;
- X datablock->SeqNum = 1;
- X datablock->NextData = 0;
- X datablock->DataSize = strlen(msgbuf);
- X strcpy((char *)datablock->Data, msgbuf);
- X
- X fixchecksum(datablock, &datablock->Checksum);
- X }
- X
- X if (!writeblock(datablock, datablocknum)) {
- X print("Error writing file data block to disk\n");
- X cleanup(10);
- X }
- X
- X /*
- X * Now fix up datablock pointers in file header
- X */
- X headers[0].FirstBlock = datablocknum;
- X headers[0].DataBlocks[71] = datablocknum;
- X
- X /*
- X * All the data blocks have been allocated correctly; now
- X * fix up the data checksums for each block. When the checksum
- X * is correct, all the longwords in the block will add up to zero
- X * (no carry when overflow occurs).
- X */
- X for (i = 0; i < numheaders; i++)
- X fixchecksum(&headers[i], &headers[i].Checksum);
- X
- X /*
- X * Finally, write all the file blocks back to disk. Note that
- X * they are written back to disk in reverse order. This way, the
- X * file header itself is the last thing to get written, so if an
- X * error occurs before hand, it won't be left in an inconsistent
- X * state.
- X */
- X chkabort(); /* Give user a final chance to abort */
- X for (i = numheaders - 1; i >= 0; i--) {
- X if (!writeblock(&headers[i], headers[i].OwnKey)) {
- X print("Error writing file headers to disk\n");
- X cleanup(10);
- X }
- X }
- X}
- X
- X
- X/*
- X * mainline()
- X * ----------
- X */
- Xvoid main(argc,argv)
- Xint argc;
- Xchar **argv;
- X{
- X unsigned int start, end; /* Cylinder numbers */
- X char *p;
- X
- X#define NONUM(x) (!isdigit(argv[x][0]))
- X
- X if (argc != 4 || NONUM(2) || NONUM(3)) {
- X help();
- X cleanup(10);
- X }
- X
- X /*
- X * Strip off trailing dir and filenames to get device name
- X */
- X pathname = argv[1];
- X strcpy(devname, pathname);
- X
- X for (p = devname; *p && *p != ':'; p++)
- X ;
- X if (*p != ':') {
- X print("The pathname must include both a device and a filename.\n");
- X cleanup(10);
- X }
- X p++; /* Skip over colon at end of device name */
- X *p = '\0';
- X
- X if (strlen(pathname) <= strlen(devname)) {
- X print("The pathname must include both a device and a filename.\n");
- X cleanup(10);
- X }
- X start = atoi(argv[2]);
- X end = atoi(argv[3]);
- X
- X if (!GetVolume(devname, diskdev)) {
- X print2(devname, " is not a valid disk device\n");
- X cleanup(10);
- X }
- X
- X if (start > end) {
- X print("Start track is greater than end track.\n");
- X cleanup(10);
- X }
- X
- X if (end >= diskdev->numcyl) {
- X print3("Maximum end track on ", devname, " is ");
- X print2(numtostr(diskdev->numcyl - 1), ".\n");
- X cleanup(10);
- X }
- X
- X if (!diskdev->isknown) {
- X print(
- X"Sorry, only Old Filing System and Fast Filing System are supported.\n");
- X cleanup(10);
- X }
- X
- X if (diskdev->blocksize != 512) {
- X print(
- X"Sorry, only devices with 512 byte blocks can be handled at present.\n");
- X cleanup(10);
- X }
- X
- X if (diskdev->numblocks > (25 * 4064)) {
- X print("Sorry, this version doesn't support drives > 50 Mb\n");
- X cleanup(10);
- X }
- X
- X diskport = (MSGPORT *)DeviceProc(devname);
- X if (!diskport) {
- X print3("Can't locate process for device ", devname, "\n");
- X cleanup(10);
- X }
- X
- X /*
- X * Everything seems in order, so lets try and create the dummy file.
- X * After creating it, we flush the disk buffers etc. to ensure that
- X * the disk bitmap is current.
- X */
- X filehandle = Open(pathname, MODE_NEWFILE);
- X if (!filehandle) {
- X print3("Couldn't open file ", pathname, ".\n");
- X cleanup(10);
- X }
- X Close(filehandle); filehandle = NULL;
- X lock = Lock(pathname, ACCESS_READ);
- X if (!lock) {
- X print3("Strangely, file ", pathname, " can no longer be accessed.\n");
- X cleanup(314); /* pi -- let's be weird */
- X }
- X filekey = ((struct FileLock *)BTOC(lock))->fl_Key;
- X flushdisk(diskport);
- X
- X /*
- X * Assuming everthing is still okay, the next step is to read in
- X * the root block and do some checks to make sure we can do the
- X * allocation.
- X */
- X opendev();
- X inhibit(diskport, TRUE);
- X inhibited = TRUE;
- X readrootblock();
- X if (rootblock->BitmapFlag != -1) {
- X print3("tfile: Bitmap for ", devname, " is not up to date.\n");
- X cleanup(10);
- X }
- X
- X /*
- X * Read in bitmap, and mark all the blocks on the desired tracks
- X * as in-use. If any of these blocks are already in use, then
- X * abort with an error.
- X */
- X readbitmap();
- X if (!filltracks(start, end)) {
- X print3("Tracks ",numtostr(start)," to ");
- X print2(numtostr(end)," contain AmigaDOS data.\n");
- X cleanup(10);
- X }
- X
- X /*
- X * Now allocate file header blocks to store the AmigaDOS pointers
- X * to each block in the reserved tracks in. The memory copy of
- X * the bitmap is modified to reflect these additional blocks.
- X * Then the new blocks are written back to disk, and the
- X * file header of the existing file is updated to reflect the
- X * additional data blocks.
- X */
- X createfileheaders(filekey,start,end);
- X
- X /*
- X * Everything is now complete, so all that remains to be done
- X * is to write back the new bitmap, update the root block and
- X * exit.
- X */
- X writebitmap();
- X cleanup(0);
- X}
- END_OF_FILE
- if test 38195 -ne `wc -c <'src/tfile.c'`; then
- echo shar: \"'src/tfile.c'\" unpacked with wrong size!
- fi
- # end of 'src/tfile.c'
- fi
- echo shar: End of archive 2 \(of 2\).
- cp /dev/null ark2isdone
- MISSING=""
- for I in 1 2 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked both archives.
- rm -f ark[1-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
- --
- Submissions to comp.sources.amiga and comp.binaries.amiga should be sent to:
- amiga@cs.odu.edu
- or amiga@xanth.cs.odu.edu ( obsolescent mailers may need this address )
- or ...!uunet!xanth!amiga ( very obsolescent mailers need this address )
-
- Comments, questions, and suggestions s should be addressed to ``amiga-request''
- (only use ``amiga'' for submissions) at the above addresses.
-